"""
抖音开放平台API测试

测试DouYinAPI类的功能，使用mock模拟请求，避免实际调用API。
"""

import unittest
from unittest.mock import patch, MagicMock
import json
from cn_api_adapters import DouYinAPI
from cn_api_adapters.common.exceptions import APIError, AuthenticationError


class TestDouYinAPI(unittest.TestCase):
    """测试DouYinAPI类的功能"""
    
    def setUp(self):
        """设置测试环境"""
        self.client_key = "test_client_key"
        self.client_secret = "test_client_secret"
        self.api = DouYinAPI(
            client_key=self.client_key,
            client_secret=self.client_secret,
            debug=False
        )
    
    def test_get_authorization_url(self):
        """测试获取授权URL"""
        redirect_uri = "https://example.com/callback"
        scope = ["user_info", "video.create"]
        state = "test_state"
        
        # 获取授权URL
        auth_url = self.api.get_authorization_url(redirect_uri, scope, state)
        
        # 验证URL是否正确构建
        self.assertIn("https://open.douyin.com/platform/oauth/connect", auth_url)
        self.assertIn(f"client_key={self.client_key}", auth_url)
        self.assertIn(f"redirect_uri={redirect_uri}", auth_url)
        self.assertIn("response_type=code", auth_url)
        self.assertIn("scope=user_info%2Cvideo.create", auth_url)
        self.assertIn(f"state={state}", auth_url)
    
    @patch('cn_api_adapters.douyin.douyin_api.DouYinAPI._request')
    def test_get_access_token_by_code(self, mock_request):
        """测试通过授权码获取AccessToken"""
        # 模拟成功响应
        mock_response = {
            "access_token": "mock_access_token",
            "refresh_token": "mock_refresh_token",
            "expires_in": 7200,
            "open_id": "mock_open_id",
            "scope": "user_info,video.create"
        }
        mock_request.return_value = mock_response
        
        # 通过授权码获取token
        code = "test_code"
        redirect_uri = "https://example.com/callback"
        result = self.api.get_access_token_by_code(code, redirect_uri)
        
        # 验证结果
        self.assertEqual(result, mock_response)
        self.assertEqual(self.api._access_token, "mock_access_token")
        self.assertEqual(self.api._refresh_token, "mock_refresh_token")
        mock_request.assert_called_once_with(
            "POST",
            "https://open.douyin.com/oauth/access_token",
            json={
                "client_key": self.client_key,
                "client_secret": self.client_secret,
                "code": code,
                "grant_type": "authorization_code",
                "redirect_uri": redirect_uri
            }
        )
    
    @patch('cn_api_adapters.douyin.douyin_api.DouYinAPI._request')
    def test_refresh_access_token(self, mock_request):
        """测试刷新AccessToken"""
        # 模拟成功响应
        mock_response = {
            "access_token": "new_access_token",
            "refresh_token": "new_refresh_token",
            "expires_in": 7200,
            "open_id": "mock_open_id"
        }
        mock_request.return_value = mock_response
        
        # 刷新token
        refresh_token = "old_refresh_token"
        result = self.api.refresh_access_token(refresh_token)
        
        # 验证结果
        self.assertEqual(result, mock_response)
        self.assertEqual(self.api._access_token, "new_access_token")
        self.assertEqual(self.api._refresh_token, "new_refresh_token")
        mock_request.assert_called_once_with(
            "POST",
            "https://open.douyin.com/oauth/refresh_token",
            json={
                "client_key": self.client_key,
                "client_secret": self.client_secret,
                "grant_type": "refresh_token",
                "refresh_token": refresh_token
            }
        )
    
    def test_set_access_token(self):
        """测试设置AccessToken"""
        # 设置token
        self.api.set_access_token("test_access_token", "test_refresh_token")
        
        # 验证设置结果
        self.assertEqual(self.api._access_token, "test_access_token")
        self.assertEqual(self.api._refresh_token, "test_refresh_token")
        
        # 只设置access_token
        self.api.set_access_token("only_access_token")
        self.assertEqual(self.api._access_token, "only_access_token")
        # refresh_token应该保持不变
        self.assertEqual(self.api._refresh_token, "test_refresh_token")
    
    @patch('cn_api_adapters.douyin.douyin_api.DouYinAPI._request')
    def test_get_user_info(self, mock_request):
        """测试获取用户信息"""
        # 先设置access_token
        self.api.set_access_token("test_access_token")
        
        # 模拟成功响应
        mock_response = {
            "data": {
                "open_id": "test_open_id",
                "union_id": "test_union_id",
                "nickname": "测试用户",
                "avatar": "http://example.com/avatar.jpg"
            },
            "error_code": 0,
            "description": "success"
        }
        mock_request.return_value = mock_response
        
        # 获取用户信息
        result = self.api.get_user_info()
        
        # 验证结果
        self.assertEqual(result, mock_response)
        mock_request.assert_called_once_with(
            "GET",
            "https://open.douyin.com/oauth/userinfo",
            params={"access_token": "test_access_token"}
        )
    
    @patch('cn_api_adapters.douyin.douyin_api.DouYinAPI._request')
    def test_upload_video(self, mock_request):
        """测试上传视频"""
        # 先设置access_token
        self.api.set_access_token("test_access_token")
        
        # 模拟成功响应
        mock_response = {
            "data": {
                "video_id": "mock_video_id",
                "upload_addr": {
                    "endpoint": "https://example.com/upload",
                    "form_data": {}
                }
            },
            "error_code": 0,
            "description": "success"
        }
        mock_request.return_value = mock_response
        
        # 模拟视频文件
        video_file = b"mock_video_data"
        file_name = "test_video.mp4"
        title = "测试视频"
        
        # 上传视频
        result = self.api.upload_video(video_file, file_name, title)
        
        # 验证结果
        self.assertEqual(result, mock_response)
        mock_request.assert_called_once()
        # 检查调用参数
        call_args = mock_request.call_args
        self.assertEqual(call_args[0][0], "POST")
        self.assertEqual(call_args[0][1], "https://open.douyin.com/video/upload/")
        self.assertEqual(call_args[1]["params"], {"access_token": "test_access_token"})
    
    @patch('cn_api_adapters.douyin.douyin_api.DouYinAPI._request')
    def test_publish_video(self, mock_request):
        """测试发布视频"""
        # 先设置access_token
        self.api.set_access_token("test_access_token")
        
        # 模拟成功响应
        mock_response = {
            "data": {
                "item_id": "mock_item_id"
            },
            "error_code": 0,
            "description": "success"
        }
        mock_request.return_value = mock_response
        
        # 发布视频
        publish_data = {
            "text": "测试视频描述",
            "video_id": "test_video_id",
            "cover_tsp": 1000
        }
        result = self.api.publish_video(**publish_data)
        
        # 验证结果
        self.assertEqual(result, mock_response)
        mock_request.assert_called_once_with(
            "POST",
            "https://open.douyin.com/video/create/",
            params={"access_token": "test_access_token"},
            json=publish_data
        )
    
    @patch('cn_api_adapters.douyin.douyin_api.DouYinAPI._request')
    def test_get_comments(self, mock_request):
        """测试获取评论列表"""
        # 先设置access_token
        self.api.set_access_token("test_access_token")
        
        # 模拟成功响应
        mock_response = {
            "data": {
                "comments": [
                    {
                        "cid": "comment1",
                        "text": "评论内容",
                        "create_time": 1234567890
                    }
                ],
                "has_more": False,
                "cursor": ""
            },
            "error_code": 0,
            "description": "success"
        }
        mock_request.return_value = mock_response
        
        # 获取评论列表
        result = self.api.get_comments("test_item_id", count=10)
        
        # 验证结果
        self.assertEqual(result, mock_response)
        mock_request.assert_called_once_with(
            "GET",
            "https://open.douyin.com/comment/list/",
            params={
                "access_token": "test_access_token",
                "item_id": "test_item_id",
                "count": 10
            }
        )
    
    @patch('cn_api_adapters.douyin.douyin_api.DouYinAPI._request')
    def test_create_mini_app_qrcode(self, mock_request):
        """测试创建小程序二维码"""
        # 模拟成功响应（二进制数据）
        mock_qrcode_data = b"mock_qrcode_binary_data"
        mock_request.return_value = mock_qrcode_data
        
        # 创建小程序二维码
        result = self.api.create_mini_app_qrcode(
            app_id="test_app_id",
            page_path="pages/index/index",
            scene="test_scene",
            width=430
        )
        
        # 验证结果
        self.assertEqual(result, mock_qrcode_data)
        mock_request.assert_called_once_with(
            "GET",
            "https://open.douyin.com/miniapp/qrcode/get",
            params={
                "access_token": "test_client_key",  # 注意这里使用的是client_key
                "app_id": "test_app_id",
                "page": "pages/index/index",
                "scene": "test_scene",
                "width": 430
            },
            response_content_type="binary"
        )
    
    @patch('cn_api_adapters.douyin.douyin_api.DouYinAPI._request')
    def test_api_error_handling(self, mock_request):
        """测试API错误处理"""
        # 模拟API错误响应
        mock_request.side_effect = APIError("API Error")
        
        # 验证抛出异常
        with self.assertRaises(APIError):
            self.api.get_access_token_by_code("test_code", "https://example.com/callback")


if __name__ == '__main__':
    unittest.main()